package xmu.crms.config.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import xmu.crms.entity.User;
import xmu.crms.exception.UserNotFoundException;
import xmu.crms.exception.WechatLoginException;
import xmu.crms.mapper.AuthMapper;
import xmu.crms.util.JwtUtil;
import xmu.crms.vo.SignInVO;

import java.io.IOException;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;

/**
 * 实现小程序登录的校验
 *
 * @author status200
 * @date 2017/12/24
 */
@Service
public class AuthServiceImpl {

    private final String wechatAuthorizationUrl = "https://api.weixin.qq.com/sns/jscode2session?appid={appid}&secret={secret}&js_code={js_code}&grant_type={grant_type}";

    private final String grantType = "authorization_code";

    @Autowired
    private AuthMapper authMapper;

    @Autowired
    private RestTemplate restTemplate;


    /**
     * 向微信服务器发送请求，获得openid与session_key
     *
     * @param jsCode
     * @return
     * @throws IOException
     */
    public MinProgramAuthorization doWechatLogin(String jsCode) throws IOException,WechatLoginException {

        Map<String, String> params = new HashMap<>(20);
        params.put("appid", SecurityConstant.WECHAT_APP_ID);
        params.put("secret", SecurityConstant.WECHAT_APP_SECRET);
        params.put("js_code", jsCode);
        params.put("grant_type", grantType);

        // 向微信服务器发送请求获取认证信息
        // 服务端返回的类型是text/plain
        // 不能直接使用对象
        String authString = restTemplate.getForObject(wechatAuthorizationUrl, String.class, params);

        ObjectMapper objectMapper = new ObjectMapper();

        MinProgramAuthorization authorization = objectMapper.readValue(authString, MinProgramAuthorization.class);

        // 如果发生错误,抛出异常
        if(authorization.getErrCode() != null) {
            throw new WechatLoginException(String.format("wechat login error!errorCode:%d,errorMessage:%s", authorization.getErrCode(), authorization.getErrMsg()));
        }

        return authorization;
    }

    /**
     * 小程序在本程序的登录。
     * 产生jwt，同时设置一些必要信息。
     *
     * @param openId
     * @return
     */
    public SignInVO doMyLogin(String openId) throws UserNotFoundException {
        User user = authMapper.getUserByOpenId(openId);
        if (user == null) {
            throw new UserNotFoundException(String.format("User with openId %s not found! This user does not sign up.", openId));
        } else {
            return genSignVO(user);
        }
    }

    /**
     * 生成包含登录信息的vo
     *
     * @param user
     * @return
     */
    public SignInVO genSignVO(User user) {
        SignInVO signIn = new SignInVO();
        Map<String, Object> userClaims = new HashMap<>(20);

        userClaims.put("id", user.getId());
        if (user.getType() != null) {
            userClaims.put("type", user.getType() == 1 ? "teacher" : "student");
        } else {
            userClaims.put("type", null);
        }
        userClaims.put("name", user.getName());

        signIn.setJwt(JwtUtil.generateToken(userClaims));
        signIn.setId((BigInteger)userClaims.get("id"));
        signIn.setName((String)userClaims.get("name"));
        signIn.setType((String)userClaims.get("type"));

        return signIn;
    }

    /**
     * 在数据库里创建新用户
     *
     * @param openId
     * @return
     */
    public User createNewUser(String openId) {
        User user = new User();
        user.setOpenid(openId);

        return authMapper.insertUserByOpenId(user) ? user : null;
    }
}
